1
2
3
4
5
6
7
8
9
10
11
12
13 package org.apache.tapestry5.internal.services;
14
15 import org.apache.tapestry5.internal.parser.*;
16 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
17 import org.apache.tapestry5.ioc.Locatable;
18 import org.apache.tapestry5.ioc.Location;
19 import org.apache.tapestry5.ioc.Resource;
20 import org.apache.tapestry5.ioc.internal.util.AbstractResource;
21 import org.apache.tapestry5.ioc.internal.util.ClasspathResource;
22 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
23 import org.apache.tapestry5.ioc.internal.util.TapestryException;
24 import org.apache.tapestry5.test.TapestryRunnerConstants;
25 import org.testng.annotations.DataProvider;
26 import org.testng.annotations.Test;
27
28 import java.util.Arrays;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32
33 import static java.lang.String.format;
34
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.net.URL;
38
39
40
41
42 public class TemplateParserImplTest extends InternalBaseTestCase
43 {
44
45 private TemplateParser getParser()
46 {
47 return this.getService(TemplateParser.class);
48 }
49
50 private synchronized ComponentTemplate parse(String file)
51 {
52 Resource resource = getResource(file);
53
54 return getParser().parseTemplate(resource);
55 }
56
57 private synchronized List<TemplateToken> tokens(String file)
58 {
59 return parse(file).getTokens();
60 }
61
62 private Resource getResource(String file)
63 {
64 String packageName = getClass().getPackage().getName();
65
66 String path = packageName.replace('.', '/') + "/" + file;
67
68 ClassLoader loader = getClass().getClassLoader();
69
70 return new ClasspathResource(loader, path);
71 }
72
73 @SuppressWarnings("unchecked")
74 private <T extends TemplateToken> T get(List l, int index)
75 {
76 Object raw = l.get(index);
77
78 return (T) raw;
79 }
80
81 private void checkType(List<TemplateToken> l, int index, TokenType expected)
82 {
83 assertEquals(l.get(index).getTokenType(), expected);
84 }
85
86 private void checkLine(Locatable l, int expectedLineNumber)
87 {
88 assertEquals(l.getLocation().getLine(), expectedLineNumber);
89 }
90
91 @Test
92 public void just_HTML()
93 {
94 Resource resource = getResource("justHTML.tml");
95
96 ComponentTemplate template = getParser().parseTemplate(resource);
97
98 assertSame(template.getResource(), resource);
99
100 assertFalse(template.usesStrictMixinParameters());
101
102 List<TemplateToken> tokens = template.getTokens();
103
104
105
106 assertEquals(tokens.size(), 20);
107
108 StartElementToken t0 = get(tokens, 0);
109
110
111
112 assertEquals(t0.name, "html");
113 assertEquals(t0.namespaceURI, "");
114 checkLine(t0, 1);
115
116 TextToken t1 = get(tokens, 1);
117
118 assertEquals(t1.text, "\n ");
119
120 StartElementToken t2 = get(tokens, 2);
121 assertEquals(t2.name, "head");
122 checkLine(t2, 2);
123
124 TextToken t5 = get(tokens, 5);
125 assertEquals(t5.text, "title");
126 checkLine(t5, 3);
127
128 get(tokens, 6);
129
130 StartElementToken t12 = get(tokens, 12);
131 assertEquals(t12.name, "p");
132
133 AttributeToken t13 = get(tokens, 13);
134 assertEquals(t13.name, "class");
135 assertEquals(t13.value, "important");
136 assertEquals(t13.namespaceURI, "");
137
138 TextToken t14 = get(tokens, 14);
139
140 assertEquals(t14.text.replaceAll("\\s+", " ").trim(), "Tapestry rocks! Line 2");
141
142
143 checkLine(t14, 6);
144 }
145
146 @Test
147 public void namespaced_element()
148 {
149 Resource resource = getResource("namespaced_element.tml");
150
151 ComponentTemplate template = getParser().parseTemplate(resource);
152
153 assertSame(template.getResource(), resource);
154
155 List<TemplateToken> tokens = template.getTokens();
156
157
158
159 assertEquals(tokens.size(), 8);
160
161 StartElementToken t0 = get(tokens, 0);
162
163 String expectedURI = "http://foo.com";
164
165 assertEquals(t0.namespaceURI, expectedURI);
166 assertEquals(t0.name, "bar");
167
168 DefineNamespacePrefixToken t1 = get(tokens, 1);
169
170 assertEquals(t1.namespacePrefix, "foo");
171 assertEquals(t1.namespaceURI, expectedURI);
172
173 AttributeToken t2 = get(tokens, 2);
174
175 assertEquals(t2.name, "biff");
176 assertEquals(t2.value, "baz");
177 assertEquals(t2.namespaceURI, expectedURI);
178
179 StartElementToken t4 = get(tokens, 4);
180
181 assertEquals(t4.namespaceURI, "");
182 assertEquals(t4.name, "gnip");
183
184
185 }
186
187 @Test
188 public void container_element()
189 {
190 List<TemplateToken> tokens = tokens("container_element.tml");
191
192 assertEquals(tokens.size(), 4);
193
194 TextToken t0 = get(tokens, 0);
195
196 assertEquals(t0.text.trim(), "A bit of text.");
197
198 StartElementToken t1 = get(tokens, 1);
199
200 assertEquals(t1.name, "foo");
201
202 EndElementToken t2 = get(tokens, 2);
203
204 assertNotNull(t2);
205
206 TextToken t3 = get(tokens, 3);
207
208 assertEquals(t3.text.trim(), "Some more text.");
209 }
210
211 @Test
212 public void xml_entity()
213 {
214 List<TemplateToken> tokens = tokens("xmlEntity.tml");
215
216 assertEquals(tokens.size(), 3);
217
218 TextToken t = get(tokens, 1);
219
220
221
222
223 assertEquals(t.text.trim(), "lt:< gt:> amp:&");
224 }
225
226 @Test
227 public void html_entity()
228 {
229 String expectedURI = "http://www.w3.org/1999/xhtml";
230
231 List<TemplateToken> tokens = tokens("html_entity.tml");
232
233 assertEquals(tokens.size(), 5);
234
235 DTDToken t0 = get(tokens, 0);
236
237 assertEquals(t0.name, "html");
238 assertEquals(t0.publicId, "-//W3C//DTD XHTML 1.0 Transitional//EN");
239 assertEquals(t0.systemId, "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");
240
241 StartElementToken t1 = get(tokens, 1);
242
243 assertEquals(t1.namespaceURI, expectedURI);
244 assertEquals(t1.name, "html");
245
246 DefineNamespacePrefixToken t2 = get(tokens, 2);
247
248 assertEquals(t2.namespaceURI, expectedURI);
249 assertEquals(t2.namespacePrefix, "");
250
251
252 TextToken t = get(tokens, 3);
253
254
255
256
257
258
259
260
261 assertEquals(t.text.trim(), "nbsp:[\u00a0]");
262 }
263
264 @Test
265 public void cdata()
266 {
267 List<TemplateToken> tokens = tokens("cdata.tml");
268
269
270
271 assertEquals(tokens.size(), 5);
272
273 CDATAToken t = get(tokens, 2);
274
275 assertEquals(t.content, "CDATA: <foo> & <bar> and <baz>");
276 checkLine(t, 2);
277 }
278
279 @Test
280 public void comment()
281 {
282 List<TemplateToken> tokens = tokens("comment.tml");
283
284
285
286 assertEquals(tokens.size(), 3);
287
288 CommentToken token1 = get(tokens, 1);
289
290 assertEquals(token1.comment, " Single line comment ");
291 }
292
293 @Test
294 public void multiline_comment()
295 {
296 List<TemplateToken> tokens = tokens("multilineComment.tml");
297
298
299
300 assertEquals(tokens.size(), 5);
301
302 CommentToken t = get(tokens, 2);
303
304 String comment = t.comment.trim().replaceAll("\\s+", " ");
305
306 assertEquals(comment, "Line one Line two Line three");
307 }
308
309 @Test
310 public void component()
311 {
312 List<TemplateToken> tokens = tokens("component.tml");
313
314 assertEquals(tokens.size(), 6);
315
316 StartComponentToken t = get(tokens, 2);
317 assertEquals(t.getId(), "fred");
318 assertEquals(t.getComponentType(), "somecomponent");
319 assertNull(t.getMixins());
320 checkLine(t, 2);
321
322 get(tokens, 3);
323 }
324
325 @Test
326 public void component_with_body()
327 {
328 List<TemplateToken> tokens = tokens("componentWithBody.tml");
329
330 assertEquals(tokens.size(), 7);
331
332 get(tokens, 2);
333
334 TextToken t = get(tokens, 3);
335
336 assertEquals(t.text.trim(), "fred's body");
337
338 get(tokens, 4);
339 }
340
341
342
343
344 @Test
345 public void comment_element_ignored()
346 {
347 List<TemplateToken> tokens = tokens("comment_element_ignored.tml");
348
349 assertEquals(tokens.size(), 8);
350
351 get(tokens, 2);
352
353 TextToken t = get(tokens, 3);
354
355 assertEquals(t.text.trim(), "fred's body");
356
357 EndElementToken end5 = get(tokens, 5);
358 EndElementToken end7 = get(tokens, 7);
359 }
360
361 @Test
362 public void root_element_is_component()
363 {
364 List<TemplateToken> tokens = tokens("root_element_is_component.tml");
365
366 assertEquals(tokens.size(), 3);
367
368 StartComponentToken start = get(tokens, 0);
369
370 assertEquals(start.getId(), "fred");
371 assertEquals(start.getComponentType(), "Fred");
372 assertNull(start.getElementName());
373
374 AttributeToken attr = get(tokens, 1);
375
376 assertEquals(attr.name, "param");
377 assertEquals(attr.value, "value");
378
379 assertTrue(EndElementToken.class.isInstance(tokens.get(2)));
380 }
381
382 @Test
383 public void instrumented_element()
384 {
385 ComponentTemplate template = parse("instrumented_element.tml");
386 List<TemplateToken> tokens = template.getTokens();
387
388 assertEquals(tokens.size(), 3);
389
390 StartComponentToken start = get(tokens, 0);
391
392 assertEquals(start.getId(), "fred");
393 assertEquals(start.getComponentType(), "Fred");
394 assertEquals(start.getElementName(), "html");
395
396 AttributeToken attr = get(tokens, 1);
397
398 assertEquals(attr.name, "param");
399 assertEquals(attr.value, "value");
400
401 assertTrue(EndElementToken.class.isInstance(tokens.get(2)));
402
403 assertEquals(template.getComponentIds().keySet(), Arrays.asList("fred"));
404 }
405
406 @Test
407 public void body_element()
408 {
409 List<TemplateToken> tokens = tokens("body_element.tml");
410
411
412 assertEquals(tokens.size(), 5);
413
414
415
416 assertTrue(BodyToken.class.isInstance(get(tokens, 2)));
417 }
418
419 @Test
420 public void component_with_parameters()
421 {
422 List<TemplateToken> tokens = tokens("componentWithParameters.tml");
423
424 assertEquals(tokens.size(), 9);
425
426 TemplateToken templateToken = get(tokens, 2);
427 Location l = templateToken.getLocation();
428
429 AttributeToken t1 = get(tokens, 3);
430
431
432
433
434 assertEquals(t1.name, "cherry");
435 assertEquals(t1.value, "bomb");
436 assertSame(t1.getLocation(), l);
437
438 AttributeToken t2 = get(tokens, 4);
439 assertEquals(t2.name, "align");
440 assertEquals(t2.value, "right");
441 assertSame(t2.getLocation(), l);
442
443 TextToken t3 = get(tokens, 5);
444
445 assertEquals(t3.text.trim(), "fred's body");
446
447 get(tokens, 6);
448 }
449
450 @Test
451 public void component_with_mixins()
452 {
453 List<TemplateToken> tokens = tokens("component_with_mixins.tml");
454
455 assertEquals(tokens.size(), 4);
456
457 StartComponentToken token1 = get(tokens, 1);
458
459 assertEquals(token1.getId(), "fred");
460 assertEquals(token1.getComponentType(), "comp");
461 assertEquals(token1.getMixins(), "Barney");
462 }
463
464 @Test
465 public void empty_string_mixins_is_null()
466 {
467 List<TemplateToken> tokens = tokens("empty_string_mixins_is_null.tml");
468
469 assertEquals(tokens.size(), 6);
470
471 StartComponentToken t = get(tokens, 2);
472
473 assertEquals(t.getId(), "fred");
474
475 assertNull(t.getComponentType());
476 assertNull(t.getMixins());
477 }
478
479 @Test
480 public void component_ids()
481 {
482 ComponentTemplate template = parse("component_ids.tml");
483
484 Map<String, Location> map = template.getComponentIds();
485
486 assertEquals(map.keySet(), CollectionFactory.newSet(Arrays.asList("bomb", "border", "zebra")));
487 }
488
489 @Test
490 public void expansions_in_normal_text()
491 {
492 List<TemplateToken> tokens = tokens("expansions_in_normal_text.tml");
493
494 assertEquals(tokens.size(), 7);
495
496 TextToken t1 = get(tokens, 1);
497
498 assertEquals(t1.text.trim(), "Expansion #1[");
499
500 ExpansionToken t2 = get(tokens, 2);
501 assertEquals(t2.getExpression(), "expansion1");
502
503 TextToken t3 = get(tokens, 3);
504 assertEquals(t3.text.replaceAll("\\s+", " "), "] Expansion #2[");
505
506 ExpansionToken t4 = get(tokens, 4);
507 assertEquals(t4.getExpression(), "expansion2");
508
509 TextToken t5 = get(tokens, 5);
510 assertEquals(t5.text.trim(), "]");
511 }
512
513 @Test
514 public void expansions_must_be_on_one_line()
515 {
516 List<TemplateToken> tokens = tokens("expansions_must_be_on_one_line.tml");
517
518 assertEquals(tokens.size(), 3);
519
520 TextToken t1 = get(tokens, 1);
521
522 assertEquals(t1.text.replaceAll("\\s+", " "), " ${expansions must be on a single line} ");
523 }
524
525 @Test
526 public void multiple_expansions_on_one_line()
527 {
528 List<TemplateToken> tokens = tokens("multiple_expansions_on_one_line.tml");
529
530 assertEquals(tokens.size(), 10);
531
532 ExpansionToken token3 = get(tokens, 3);
533
534 assertEquals(token3.getExpression(), "classLoader");
535
536 TextToken token4 = get(tokens, 4);
537
538 assertEquals(token4.text, " [");
539
540 ExpansionToken token5 = get(tokens, 5);
541
542 assertEquals(token5.getExpression(), "classLoader.class.name");
543
544 TextToken token6 = get(tokens, 6);
545
546 assertEquals(token6.text, "]");
547 }
548
549 @Test
550 public void expansions_not_allowed_in_cdata()
551 {
552 List<TemplateToken> tokens = tokens("expansions_not_allowed_in_cdata.tml");
553
554 assertEquals(tokens.size(), 5);
555
556 CDATAToken t2 = get(tokens, 2);
557
558 assertEquals(t2.content, "${not-an-expansion}");
559 }
560
561 @Test
562 public void expansions_not_allowed_in_attributes()
563 {
564 List<TemplateToken> tokens = tokens("expansions_not_allowed_in_attributes.tml");
565
566 assertEquals(tokens.size(), 3);
567
568 AttributeToken token1 = get(tokens, 1);
569
570 assertEquals(token1.name, "exp");
571 assertEquals(token1.value, "${not-an-expansion}");
572 }
573
574 @Test
575 public void expansions_with_maps()
576 {
577 List<TemplateToken> tokens = tokens("expansions_with_maps.tml");
578
579 assertEquals(tokens.size(), 11);
580
581
582
583 ExpansionToken expansion = get(tokens, 2);
584 assertEquals(expansion.getExpression(), "{}", "Empty map parsed incorrectly in an expansion");
585
586 expansion = get(tokens, 4);
587 assertEquals(expansion.getExpression(), "{'a': 'b'}", "Non-empty map parsed incorrectly in an expansion");
588
589 expansion = get(tokens, 6);
590 assertEquals(expansion.getExpression(), "{'one': 1}", "First expansion in a line with two expansions parsed incorrectly");
591
592 expansion = get(tokens, 8);
593 assertEquals(expansion.getExpression(), "{'two': 2}", "Second expansion in a line with two expansions parsed incorrectly");
594 }
595
596 @Test
597 public void expansion_whitespace_trimmed()
598 {
599 List<TemplateToken> tokens = tokens("expansions_with_whitespace.tml");
600
601 assertEquals(tokens.size(), 9);
602
603 ExpansionToken expansion = get(tokens, 2);
604 assertEquals(expansion.getExpression(), "message:messagekey1");
605
606 }
607
608 @Test
609 public void parameter_element()
610 {
611 List<TemplateToken> tokens = tokens("parameter_element.tml");
612
613 ParameterToken token4 = get(tokens, 4);
614 assertEquals(token4.name, "fred");
615
616 CommentToken token6 = get(tokens, 6);
617 assertEquals(token6.comment, " fred content ");
618
619 TemplateToken token8 = get(tokens, 8);
620
621 assertEquals(token8.getTokenType(), TokenType.END_ELEMENT);
622 }
623
624
625
626
627 @Test
628 public void parameter_namespace_element()
629 {
630 List<TemplateToken> tokens = tokens("parameter_namespace_element.tml");
631
632 ParameterToken token4 = get(tokens, 4);
633 assertEquals(token4.name, "fred");
634
635 CommentToken token6 = get(tokens, 6);
636 assertEquals(token6.comment, " fred content ");
637
638 TemplateToken token8 = get(tokens, 8);
639
640 assertEquals(token8.getTokenType(), TokenType.END_ELEMENT);
641 }
642
643 @Test
644 public void complex_component_type()
645 {
646 List<TemplateToken> tokens = tokens("complex_component_type.tml");
647
648 assertEquals(tokens.size(), 4);
649
650 StartComponentToken token1 = get(tokens, 1);
651
652 assertEquals(token1.getComponentType(), "subfolder/nifty");
653 }
654
655
656
657
658 @Test
659 public void component_inside_library_namespace()
660 {
661 List<TemplateToken> tokens = tokens("component_inside_library_namespace.tml");
662
663 assertEquals(tokens.size(), 4);
664
665 StartComponentToken token1 = get(tokens, 1);
666
667 assertEquals(token1.getComponentType(), "subfolder/nifty");
668 }
669
670 @Test
671 public void block_element()
672 {
673 List<TemplateToken> tokens = tokens("block_element.tml");
674
675 BlockToken token1 = get(tokens, 1);
676 assertEquals(token1.getId(), "block0");
677
678 CommentToken token2 = get(tokens, 2);
679 assertEquals(token2.comment, " block0 content ");
680
681 BlockToken token4 = get(tokens, 4);
682 assertNull(token4.getId());
683
684 CommentToken token5 = get(tokens, 5);
685 assertEquals(token5.comment, " anon block content ");
686 }
687
688 @DataProvider
689 public Object[][] parse_failure_data()
690 {
691 return new Object[][]{
692
693 {"mixin_requires_id_or_type.tml",
694 "You may not specify mixins for element <span> because it does not represent a component (which requires either an id attribute or a type attribute).",
695 2},
696
697 {"unexpected_attribute_in_parameter_element.tml",
698 "Element <parameter> does not support an attribute named 'grok'. The only allowed attribute name is 'name'.",
699 4},
700
701 {"name_attribute_of_parameter_element_omitted.tml",
702 "The name attribute of the <parameter> element must be specified.", 4},
703
704 {"name_attribute_of_parameter_element_blank.tml",
705 "The name attribute of the <parameter> element must be specified.", 4},
706
707 {"unexpected_attribute_in_block_element.tml",
708 "Element <block> does not support an attribute named 'name'. The only allowed attribute name is 'id'.",
709 3},
710
711 {"parameter_namespace_with_attributes.tml",
712 "A block parameter element does not allow any additional attributes. The element name defines the parameter name.", 4},
713
714 {"invalid_library_namespace_path.tml",
715 "The path portion of library namespace URI 'tapestry-library:subfolder/' is not valid", 2},
716
717 {"content_within_body_element.tml", "Content inside a Tapestry body element is not allowed", 2},
718
719 {"nested_content_element.tml",
720 "The <content> element may not be nested within another <content> element.", 3},
721
722 {"container_must_be_root.tml", "Element <container> is only valid as the root element of a template.",
723 3},
724
725 {"extend_must_be_root.tml", "Element <extend> is only valid as the root element of a template.", 3},
726
727 {"replace_must_be_under_extend.tml",
728 "The <replace> element may only appear directly within an extend element.", 3},
729
730 {"only_replace_within_extend.tml", "Child element of <extend> must be <replace>.", 2},
731
732 {"missing_id_in_replace_element.tml", "The <replace> element must have an id attribute.", 3},
733
734 {"extension_point_must_have_id.tml", "The <extension-point> element must have an id attribute.", 3},
735
736 {"misplaced_parameter.tml", "Block parameters are only allowed directly within component elements.",
737 5},
738
739 {"parameter_namespace_element_deprecated.tml", "The <parameter> element has been deprecated in Tapestry 5.3 in favour of 'tapestry:parameter' namespace.", 4},
740
741 };
742 }
743
744 @Test(dataProvider = "parse_failure_data")
745 public void parse_failure(String fileName, String errorMessageSubstring, int expectedLine)
746 {
747 try
748 {
749 parse(fileName);
750 unreachable();
751 } catch (TapestryException ex)
752 {
753 if (!ex.getMessage().contains(errorMessageSubstring))
754 {
755 throw new AssertionError(format("Message [%s] does not contain substring [%s].", ex.getMessage(),
756 errorMessageSubstring));
757 }
758
759 assertEquals(ex.getLocation().getLine(), expectedLine);
760 }
761 }
762
763 @DataProvider
764 public Object[][] doctype_parsed_correctly_data()
765 {
766 return new Object[][]{{"xhtml1_strict_doctype.tml"}, {"xhtml1_transitional_doctype.tml"},
767 {"xhtml1_frameset_doctype.tml"}};
768 }
769
770 @Test(dataProvider = "doctype_parsed_correctly_data")
771 public void doctype_parsed_correctly(String fileName) throws Exception
772 {
773 List<TemplateToken> tokens = tokens(fileName);
774 assertEquals(tokens.size(), 12);
775 TextToken t = get(tokens, 9);
776 assertEquals(t.text.trim(), "<Test>");
777 }
778
779 @DataProvider
780 public Object[][] doctype_token_added_correctly_data()
781 {
782 return new Object[][]{
783
784 {"xhtml1_strict_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Strict//EN",
785 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"},
786
787 {"xhtml1_transitional_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Transitional//EN",
788 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"},
789
790 {"xhtml1_frameset_doctype.tml", "html", "-//W3C//DTD XHTML 1.0 Frameset//EN",
791 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"},
792
793 {"html4_strict_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01//EN",
794 "http://www.w3.org/TR/html4/strict.dtd"},
795
796 {"html4_transitional_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01 Transitional//EN",
797 "http://www.w3.org/TR/html4/loose.dtd"},
798
799 {"html4_frameset_doctype.tml", "HTML", "-//W3C//DTD HTML 4.01 Frameset//EN",
800 "http://www.w3.org/TR/html4/frameset.dtd"},
801
802 {"system_doctype.xml", "foo", null,
803 "src/test/resources/org/apache/tapestry5/internal/services/simple.dtd"}};
804 }
805
806 @Test(dataProvider = "doctype_token_added_correctly_data")
807 public void doctype_added_correctly(String fileName, String name, String publicId, String systemId) throws Exception
808 {
809 System.setProperty("user.dir", TapestryRunnerConstants.MODULE_BASE_DIR_PATH);
810
811 List<TemplateToken> tokens = tokens(fileName);
812 DTDToken t0 = get(tokens, 0);
813 assertEquals(t0.name, name);
814 assertEquals(t0.publicId, publicId);
815 assertEquals(t0.systemId, systemId);
816 }
817
818 @Test
819 public void invalid_component_id() throws Exception
820 {
821 try
822 {
823 parse("invalid_component_id.tml");
824 unreachable();
825 } catch (RuntimeException ex)
826 {
827 assertMessageContains(ex, "Component id 'not-valid' is not valid");
828 }
829 }
830
831 @Test
832 public void invalid_block_id() throws Exception
833 {
834 try
835 {
836 parse("invalid_block_id.tml");
837 unreachable();
838 } catch (RuntimeException ex)
839 {
840 assertMessageContains(ex, "Block id 'not-valid' is not valid");
841 }
842 }
843
844
845
846
847 @Test
848 public void space_preserved_in_block() throws Exception
849 {
850 List<TemplateToken> tokens = tokens("space_preserved_in_block.tml");
851
852 TextToken token1 = get(tokens, 1);
853
854 assertEquals(token1.text, "\n" + " line in the middle\n" + " ");
855 }
856
857
858
859
860 @Test
861 public void space_preserved_in_container() throws Exception
862 {
863 List<TemplateToken> tokens = tokens("space_preserved_in_container.tml");
864
865 TextToken token0 = get(tokens, 0);
866 assertEquals(token0.text, "\n" + " ");
867
868 TextToken token2 = get(tokens, 2);
869 assertEquals(token2.text, "\n" + " some text\n" + " ");
870 }
871
872 @Test
873 public void minimal_whitespace_maintained_inside_tags() throws Exception
874 {
875 List<TemplateToken> tokens = tokens("minimal_whitespace_maintained_inside_tags.tml");
876
877
878
879
880 TextToken token1 = get(tokens, 1);
881 assertEquals(token1.text, "\nWhitespace\n");
882
883
884 TextToken token5 = get(tokens, 5);
885 assertEquals(token5.text, "\nis maintained.\n");
886 }
887
888
889
890
891 @Test
892 public void content_element() throws Exception
893 {
894 List<TemplateToken> tokens = tokens("content_element.tml");
895
896 assertEquals(tokens.size(), 5);
897
898 StartComponentToken token0 = get(tokens, 0);
899 assertEquals(token0.getElementName(), "body");
900 assertEquals(token0.getComponentType(), "layout");
901
902 StartElementToken token1 = get(tokens, 1);
903 assertEquals(token1.name, "p");
904
905 TextToken token2 = get(tokens, 2);
906
907 assertEquals(token2.text, "Page content");
908
909 checkType(tokens, 3, TokenType.END_ELEMENT);
910 checkType(tokens, 4, TokenType.END_ELEMENT);
911 }
912
913 @Test
914 public void overrides() throws Exception
915 {
916 ComponentTemplate template = parse("overrides.tml");
917
918 assertTrue(template.isExtension());
919
920 assertEquals(template.getTokens().size(), 0);
921
922 List<TemplateToken> alpha = template.getExtensionPointTokens("alpha");
923
924 assertEquals(alpha.size(), 1);
925
926 TextToken alpha0 = get(alpha, 0);
927 assertEquals(alpha0.text, "beta");
928
929 List<TemplateToken> gamma = template.getExtensionPointTokens("gamma");
930 assertEquals(gamma.size(), 3);
931
932 StartElementToken gamma0 = get(gamma, 0);
933 assertEquals(gamma0.name, "p");
934
935 TextToken gamma1 = get(gamma, 1);
936
937 assertEquals(gamma1.text, "Hi!");
938
939 checkType(gamma, 2, TokenType.END_ELEMENT);
940 }
941
942 @Test
943 public void extension_point() throws Exception
944 {
945 ComponentTemplate template = parse("extension_point.tml");
946
947 ExtensionPointToken expansion = get(template.getTokens(), 2);
948
949 assertEquals(expansion.getExtensionPointId(), "title");
950
951 List<TemplateToken> title = template.getExtensionPointTokens("title");
952
953 assertEquals(title.size(), 3);
954
955 StartElementToken title0 = get(title, 0);
956 assertEquals(title0.name, "h1");
957
958 TextToken title1 = get(title, 1);
959 assertEquals(title1.text, "Default Title");
960
961 checkType(title, 2, TokenType.END_ELEMENT);
962 }
963
964 @Test
965 public void html5_with_entities() throws Exception
966 {
967 List<TemplateToken> tokens = tokens("html5_with_entities.tml");
968
969 assertEquals(tokens.size(), 5);
970
971 DTDToken token0 = get(tokens, 0);
972 assertEquals(token0.toString(), "DTD[name=html; publicId=null; systemId=null]");
973
974 TextToken token3 = get(tokens, 3);
975
976 assertEquals(token3.text, "\u00A92011\u00A0Apache");
977 }
978
979
980
981
982 @Test
983 public void dupe_extension_point_id() throws Exception
984 {
985 try
986 {
987 tokens("dupe_extension_point_id.tml");
988 unreachable();
989 } catch (Exception ex)
990 {
991 assertMessageContains(ex, "Extension point 'batman' is already defined for this template.");
992 }
993 }
994
995 @Test
996 public void html_entities_inside_template_without_doctype_are_allowed() throws Exception
997 {
998 List<TemplateToken> tokens = tokens("html_entities.tml");
999
1000 assertEquals(tokens.size(), 3);
1001
1002 StartElementToken token0 = get(tokens, 0);
1003
1004 assertEquals(token0.name, "html");
1005
1006 TextToken token1 = get(tokens, 1);
1007
1008 assertEquals(token1.text, "\n[\u00A0]\n");
1009 }
1010
1011 @Test
1012 public void utf8_template() throws Exception
1013 {
1014 List<TemplateToken> tokens = tokens("chinese_utf-8.tml");
1015
1016 TextToken token7 = get(tokens, 7);
1017
1018 assertEquals(token7.text.trim().substring(0, 3), "\u975E\u5e38\u7b80");
1019 }
1020
1021 @Test
1022 public void block_can_nest_inside_extend() throws Exception
1023 {
1024 List<TemplateToken> tokens = tokens("block_can_nest_inside_extend.tml");
1025
1026 BlockToken token = get(tokens, 0);
1027
1028 assertEquals(token.getId(), "myBlock");
1029 }
1030
1031
1032
1033
1034
1035
1036 @Test
1037 public void default_attributes_not_included()
1038 {
1039 List<TemplateToken> tokens = tokens("default_attributes_not_included.tml");
1040
1041 assertEquals(tokens.size(), 2);
1042
1043
1044
1045 assertEquals(toString(tokens), "Start[a] End");
1046 }
1047
1048 @Test
1049 public void t54_DTDs_are_strict_about_mixin_parameters() {
1050
1051 assertTrue(parse("instrumented_element.tml").usesStrictMixinParameters());
1052 }
1053
1054 private String toString(List<TemplateToken> tokens)
1055 {
1056 StringBuilder builder = new StringBuilder();
1057 String sep = "";
1058
1059 for (TemplateToken token : tokens)
1060 {
1061 builder.append(sep).append(token.toString());
1062 sep = " ";
1063 }
1064
1065 return builder.toString();
1066 }
1067
1068 @Test
1069 public void text_from_content_not_dropped() {
1070 List<TemplateToken> tokens = tokens("TAP5-2109.tml");
1071
1072 System.out.println(tokens);
1073
1074 assertEquals(tokens.size(), 4);
1075
1076 TextToken t0 = get(tokens, 0);
1077
1078 assertEquals(t0.text.trim(), "BEGIN");
1079
1080 StartComponentToken t1 = get(tokens, 1);
1081 assertEquals(t1.getComponentType(), "somecomponent");
1082
1083 EndElementToken t2 = get(tokens, 2);
1084
1085 TextToken t3 = get(tokens, 3);
1086
1087 assertEquals(t3.text.trim(), "END");
1088 }
1089
1090 @Test
1091
1092 public void resource_that_throws_exception() throws Exception
1093 {
1094
1095 Resource resource = new AbstractResource("throwfoo") {
1096
1097 @Override
1098 public URL toURL() {
1099 return null;
1100 }
1101
1102 @Override
1103 public boolean exists() {
1104 return true;
1105 }
1106
1107 @Override
1108 protected Resource newResource(String path) {
1109 return null;
1110 }
1111
1112 @Override
1113 public InputStream openStream() throws IOException {
1114 throw new IOException("foo");
1115 }
1116 };
1117
1118
1119 try
1120 {
1121 getParser().parseTemplate(resource);
1122 unreachable();
1123 } catch (RuntimeException ex)
1124 {
1125 if (ex.getCause() instanceof TapestryException && ex.getCause().getCause() instanceof IOException)
1126 {
1127 assertMessageContains(ex, "foo");
1128 } else {
1129 throw ex;
1130 }
1131 }
1132 }
1133 }